#include "preHeader.h"
#include "GateServerSession.h"
#include "GateServerSessionHandler.h"
#include "PlayerPacketHandler.h"
#include "GateServerMgr.h"
#include "MapServer.h"
#include "Map/InstanceMgr.h"
#include "Object/PlayerMgr.h"

GateServerSession::GateServerSession()
: Session("GateServerSession")
, m_gsIdx(0)
{
}

GateServerSession::~GateServerSession()
{
}

int GateServerSession::HandlePacket(INetPacket *pck)
{
	if (IsReady() || pck->GetOpcode() < FLAG_GATE2MAP_MSG_NEED_REGISTER_BEGIN) {
		return sGateServerSessionHandler.HandlePacket(this, *pck);
	} else {
		return SessionHandleUnhandle;
	}
}

void GateServerSession::OnShutdownSession()
{
	sGateServerMgr.RemoveGateServer(this);
	WLOG("Close GateServerSession [serverId:%u gateSN:%u msSN:%u gsIdx:%u].",
		m_guid.serverId, m_guid.gateSN, m_guid.msSN, m_gsIdx);
	Session::OnShutdownSession();
}

void GateServerSession::OnRecvPacket(INetPacket *pck)
{
	switch (pck->GetOpcode()) {
	case CGM_TRANS_PLAYER_PACKET:
		TransPlayerPacket(pck);
		break;
	case CGM_TRANS_INSTANCE_PACKET:
		TransInstancePacket(pck);
		break;
	default:
		Session::OnRecvPacket(pck);
		break;
	}
}

void GateServerSession::TransInstancePacket(INetPacket *pck) const
{
	InstGUID instGuid;
	*pck >> instGuid;
	MapInstance* pMapInstance = sInstanceMgr.GetMapInstance(instGuid);
	if (pMapInstance != NULL) {
		pMapInstance->PushRecvPacket(
			InstanceService::NewInstancePacket(m_gsIdx, &pck->UnpackPacket()));
	} else {
		WLOG("Trans instance packet failed, can't find instance [%hu,%hu,%u].",
			instGuid.TID, instGuid.MAPID, instGuid.UID);
		delete pck;
	}
}

void GateServerSession::TransPlayerPacket(INetPacket *pck) const
{
	ObjGUID playerGuid;
	*pck >> playerGuid;
	playerGuid.SID = m_gsIdx;
	InstGUID instGuid = sPlayerMgr.GetPlayerInstance(playerGuid);
	if (instGuid != InstGUID_NULL) {
		MapInstance* pMapInstance = sInstanceMgr.GetMapInstance(instGuid);
		if (pMapInstance != NULL) {
			pMapInstance->PushRecvPacket(
				InstanceService::NewPlayerPacket(playerGuid, &pck->UnpackPacket()));
		} else {
			WLOG("Trans player packet failed, can't find instance [%hu,%hu,%u].",
				instGuid.TID, instGuid.MAPID, instGuid.UID);
			delete pck;
		}
	} else {
		WLOG("Trans player packet failed, can't find player (%hu,%u).",
			playerGuid.SID, playerGuid.UID);
		delete pck;
	}
}

void GateServerSession::TransPacket(uint32 sn, const INetPacket& pck)
{
	NetPacket trans(SGM_TRANS_CLIENT_PACKET);
	trans << sn;
	PushSendPacket(trans, pck);
}

void GateServerSession::TransPacket(uint32 sn, const std::string_view& data)
{
	NetPacket trans(SGM_TRANS_CLIENT_PACKET);
	trans << sn;
	PushSendPacket(trans, data);
}

void GateServerSession::TransPacket(uint32 sn,
	const INetPacket *pcks[], size_t pck_num,
	const std::string_view datas[], size_t data_num)
{
	NetPacket trans(SGM_TRANS_CLIENT_PACKET);
	trans << sn;
	const size_t FastModePckNum = 8;
	if (FastModePckNum > pck_num) {
		const INetPacket* newPcks[FastModePckNum]{ &trans };
		std::copy(pcks, pcks + pck_num, newPcks + 1);
		PushSendPacket(newPcks, pck_num + 1, datas, data_num);
	} else {
		std::vector<const INetPacket*> newPcks(pck_num + 1);
		newPcks[0] = &trans;
		std::copy(pcks, pcks + pck_num, &newPcks[1]);
		PushSendPacket(newPcks.data(), pck_num + 1, datas, data_num);
	}
}

void GateServerSession::TransPacket2Instance(
	const INetPacket& pck, uint32 msSN, InstGUID instGuid)
{
	NetPacket trans2Gate(SGM_TRANS_MAP_SERVER_PACKET);
	trans2Gate << msSN;
	NetPacket trans2MS(CGM_TRANS_INSTANCE_PACKET);
	trans2MS << instGuid;
	const INetPacket *pcks[] = {&trans2Gate, &trans2MS, &pck};
	PushSendPacket(pcks, ARRAY_SIZE(pcks), NULL, 0);
}

void GateServerSession::TransPacket2Player(
	const INetPacket& pck, uint32 msSN, ObjGUID playerGuid)
{
	NetPacket trans2Gate(SGM_TRANS_MAP_SERVER_PACKET);
	trans2Gate << msSN;
	NetPacket trans2MS(CGM_TRANS_PLAYER_PACKET);
	trans2MS << playerGuid;
	const INetPacket *pcks[] = {&trans2Gate, &trans2MS, &pck};
	PushSendPacket(pcks, ARRAY_SIZE(pcks), NULL, 0);
}

void GateServerSession::TransPacket2Social4Player(
	uint32 uid, const INetPacket& pck)
{
	NetPacket trans2Gate(SGM_TRANS_SOCIAL_SERVER_PACKET);
	NetPacket trans2Social(CGT_TRANS_SERVER_PACKET);
	NetPacket wrapper(pck.GetOpcode());
	wrapper << uid;
	const INetPacket *pcks[] = {&trans2Gate, &trans2Social, &wrapper};
	const std::string_view datas[] = {pck.CastReadableStringView()};
	PushSendPacket(pcks, ARRAY_SIZE(pcks), datas, ARRAY_SIZE(datas));
}

void GateServerSession::TransPacket2Social4Player(
	const std::string_view& info, const INetPacket& pck)
{
	NetPacket trans2Gate(SGM_TRANS_SOCIAL_SERVER_PACKET);
	NetPacket trans2Social(CGT_TRANS_SERVER_PACKET);
	NetPacket wrapper(pck.GetOpcode());
	const INetPacket *pcks[] = {&trans2Gate, &trans2Social, &wrapper};
	const std::string_view datas[] = {info, pck.CastReadableStringView()};
	PushSendPacket(pcks, ARRAY_SIZE(pcks), datas, ARRAY_SIZE(datas));
}

int GateServerSessionHandler::HandleRegister(GateServerSession *pSession, INetPacket &pck)
{
	pck >> pSession->m_guid.serverId >> pSession->m_guid.gateSN >> pSession->m_guid.msSN
		>> pSession->m_gsIdx;
	auto pGateServer = sGateServerMgr.GetGateServer(pSession->guid());
	if (pGateServer != NULL) {
		sGateServerMgr.RemoveGateServer(pGateServer);
		pGateServer->KillSession();
		pGateServer->resetGUID();
	}
	sGateServerMgr.RegisterGateServer(pSession);

	bool flagHandlers[GAME_OPCODE::CSMSG_COUNT];
	sPlayerPacketHandler.InitHandlerFlags(flagHandlers, ARRAY_SIZE(flagHandlers));

	NetPacket resp(SGM_REGISTER_RESP);
	resp.Append(flagHandlers, sizeof(flagHandlers));
	pSession->PushSendPacket(resp);

	NLOG("GateServer Register Success As [serverId:%u gateSN:%u msSN:%u gsIdx:%u].",
		pSession->m_guid.serverId, pSession->m_guid.gateSN, pSession->m_guid.msSN,
		pSession->m_gsIdx);

	return SessionHandleSuccess;
}
